package com.zondy.mapgis.android.utils;

import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

import com.zondy.mapgis.explorer.R;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Camera;
import android.graphics.Matrix;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.PopupWindow;
import android.widget.Toast;


public class Utilities {
	private static final String TAG = "Vod.Utilities";

	private Utilities() {
	}

	public static int getDefaultLruCacheSize(int precent) {
		final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
		final int cacheSize = maxMemory / precent;
		return cacheSize;
	}

	@SuppressLint("DefaultLocale")
	public static String stringForTimeAuto(int timeMs) {
		int totalSeconds = timeMs / 1000;

		int seconds = totalSeconds % 60;
		int minutes = (totalSeconds / 60) % 60;
		int hours = totalSeconds / 3600;

		if (hours > 0) {
			return String.format("%d:%02d:%02d", hours, minutes, seconds).toString();
		} else {
			return String.format("%02d:%02d", minutes, seconds).toString();
		}
	}

	@SuppressLint("DefaultLocale")
	public static String stringForTimeAuto(long timeMs) {
		long totalSeconds = timeMs / 1000;

		long seconds = totalSeconds % 60;
		long minutes = (totalSeconds / 60) % 60;
		long hours = totalSeconds / 3600;

		if (hours > 0) {
			return String.format("%d:%02d:%02d", hours, minutes, seconds).toString();
		} else {
			return String.format("%02d:%02d", minutes, seconds).toString();
		}
	}

	@SuppressLint("DefaultLocale")
	public static String formatDuration(int timeMs) {
		int totalSeconds = timeMs / 1000;

		int minutes = (totalSeconds / 60) % 60;
		int hours = totalSeconds / 3600;
		return String.format("%02d:%02d", hours, minutes).toString();

	}

	public static int calcStartAt(int page, int pageSize) {
		return (page - 1) * pageSize + 1;
	}

	public static int calcTotalPage(int totalResults, int pageSize) {
		if (totalResults % pageSize != 0) return totalResults / pageSize + 1;
		return totalResults / pageSize;
	}

	public static String md5(String text) {
		byte[] bytes;
		try {
			bytes = MessageDigest.getInstance("MD5").digest(text.getBytes());
			StringBuilder builder = new StringBuilder(bytes.length * 2);
			for (byte b : bytes) {
				builder.append(String.format("%02X", b));
			}
			return builder.toString();
		} catch (NoSuchAlgorithmException e) {
			Log.e(TAG, "md5 NoSuchAlgorithmException:" + e.getMessage());
		}
		if (!TextUtils.isEmpty(text) && text.length() > 8) return text.substring(0, 8) + text.length();
		return "";
	}

	public static void startActivitySafely(Context context, Intent intent) {
		try {
			context.startActivity(intent);
		} catch (ActivityNotFoundException e) {
			Toast.makeText(context, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
		} catch (SecurityException e) {

			Toast.makeText(context, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
			Log.e(TAG, "Launcher does not have the permission to launch " + intent
					+ ". Make sure to create a MAIN intent-filter for the corresponding activity "
					+ "or use the exported attribute for this activity.", e);
		}
	}

	public static void startActivitySafely(Context context, Intent intent, Bundle extras) {
		try {
			intent.putExtras(extras);
			context.startActivity(intent);
		} catch (ActivityNotFoundException e) {

			Toast.makeText(context, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
		} catch (SecurityException e) {

			Toast.makeText(context, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
			Log.e(TAG, "Launcher does not have the permission to launch " + intent
					+ ". Make sure to create a MAIN intent-filter for the corresponding activity "
					+ "or use the exported attribute for this activity.", e);
		}
	}

	public static void startActivityForResultSafely(Activity activity, Intent intent, int requestCode) {
		try {
			activity.startActivityForResult(intent, requestCode);
		} catch (ActivityNotFoundException e) {
			Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
		} catch (SecurityException e) {
			Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
			Log.e(TAG, "Launcher does not have the permission to launch " + intent
					+ ". Make sure to create a MAIN intent-filter for the corresponding activity "
					+ "or use the exported attribute for this activity.", e);
		}
	}

	public static String readStringFromAssets(Context context, String file) {
		InputStream is = null;
		try {
			is = context.getAssets().open(file);
			int size = is.available();
			byte[] buffer = new byte[size];
			is.read(buffer);
			return new String(buffer, "UTF-8");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (is != null) try {
				is.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return "";
	}

	/**
	 * Decode and sample down a bitmap from resources to the requested width and height.
	 * 
	 * @param res The resources object containing the image data
	 * @param resId The resource id of the image data
	 * @param reqWidth The requested width of the resulting bitmap
	 * @param reqHeight The requested height of the resulting bitmap
	 * @param cache The ImageCache used to find candidate bitmaps for use with inBitmap
	 * @return A bitmap sampled down from the original with the same aspect ratio and dimensions
	 *         that are equal to or greater than the requested width and height
	 */
	public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {

		// First decode with inJustDecodeBounds=true to check dimensions
		final BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeResource(res, resId, options);

		// Calculate inSampleSize
		options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

		// Decode bitmap with inSampleSize set
		options.inJustDecodeBounds = false;
		return BitmapFactory.decodeResource(res, resId, options);
	}

	/**
	 * Decode and sample down a bitmap from a file to the requested width and height.
	 * 
	 * @param filename The full path of the file to decode
	 * @param reqWidth The requested width of the resulting bitmap
	 * @param reqHeight The requested height of the resulting bitmap
	 * @param cache The ImageCache used to find candidate bitmaps for use with inBitmap
	 * @return A bitmap sampled down from the original with the same aspect ratio and dimensions
	 *         that are equal to or greater than the requested width and height
	 */
	public static Bitmap decodeSampledBitmapFromFile(String filename, int reqWidth, int reqHeight) {

		// First decode with inJustDecodeBounds=true to check dimensions
		final BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeFile(filename, options);

		// Calculate inSampleSize
		options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

		// Decode bitmap with inSampleSize set
		options.inJustDecodeBounds = false;
		return BitmapFactory.decodeFile(filename, options);
	}

	/**
	 * Decode and sample down a bitmap from a file input stream to the requested width and height.
	 * 
	 * @param fileDescriptor The file descriptor to read from
	 * @param reqWidth The requested width of the resulting bitmap
	 * @param reqHeight The requested height of the resulting bitmap
	 * @param cache The ImageCache used to find candidate bitmaps for use with inBitmap
	 * @return A bitmap sampled down from the original with the same aspect ratio and dimensions
	 *         that are equal to or greater than the requested width and height
	 */
	public static Bitmap decodeSampledBitmapFromDescriptor(FileDescriptor fileDescriptor, int reqWidth, int reqHeight) {
		// First decode with inJustDecodeBounds=true to check dimensions
		final BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);

		// Calculate inSampleSize
		options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

		// Decode bitmap with inSampleSize set
		options.inJustDecodeBounds = false;

		return BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
	}

	public static Bitmap decodeSampledBitmapFromStream(InputStream stream, int reqWidth, int reqHeight) {

		// First decode with inJustDecodeBounds=true to check dimensions
		final BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeStream(stream, null, options);

		// Calculate inSampleSize
		options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

		// Decode bitmap with inSampleSize set
		options.inJustDecodeBounds = false;

		return BitmapFactory.decodeStream(stream, null, options);
	}

	/**
	 * Calculate an inSampleSize for use in a {@link BitmapFactory.Options} object when decoding
	 * bitmaps using the decode* methods from {@link BitmapFactory}. This implementation calculates
	 * the closest inSampleSize that is a power of 2 and will result in the final decoded bitmap
	 * having a width and height equal to or larger than the requested width and height.
	 * 
	 * @param options An options object with out* params already populated (run through a decode*
	 *            method with inJustDecodeBounds==true
	 * @param reqWidth The requested width of the resulting bitmap
	 * @param reqHeight The requested height of the resulting bitmap
	 * @return The value to be used for inSampleSize
	 */
	public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
		// Raw height and width of image
		final int height = options.outHeight;
		final int width = options.outWidth;
		int inSampleSize = 1;

		if (height > reqHeight || width > reqWidth) {

			final int halfHeight = height / 2;
			final int halfWidth = width / 2;

			// Calculate the largest inSampleSize value that is a power of 2 and
			// keeps both
			// height and width larger than the requested height and width.
			while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {
				inSampleSize *= 2;
			}

			// This offers some additional logic in case the image has a strange
			// aspect ratio. For example, a panorama may have a much larger
			// width than height. In these cases the total pixels might still
			// end up being too large to fit comfortably in memory, so we should
			// be more aggressive with sample down the image (=larger
			// inSampleSize).

			long totalPixels = width * height / inSampleSize;

			// Anything more than 2x the requested pixels we'll sample down
			// further
			final long totalReqPixelsCap = reqWidth * reqHeight * 2;

			while (totalPixels > totalReqPixelsCap) {
				inSampleSize *= 2;
				totalPixels /= 2;
			}
		}
		return inSampleSize;
	}

	public static String getNowDay() {
		Calendar c = Calendar.getInstance();// 可以对每个时间域单独修改
		// c.set(2014, 6, 26, 17, 26, 0);
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA);
		return sdf.format(c.getTime());
	}

	// ================================时间相关操作=============================================
	private static final String PATTERN_DATE = "yyyyMMdd";
	private static final String PATTERN_DATE2 = "yyyy-MM-dd";
	private static final String PATTERN_SHORT_DATE = "MM-dd";
	private static final String PATTERN_TIME = "yyyyMMddHHmmss";
	private static final String PATTERN_MIDD_TIME = "HH:mm:ss";
	private static final String PATTERN_SHORT_TIME = "HH:mm";
	private static final String PATTERN_DATE_TIME = "MM-dd HH:mm";

	// TODO:yanbin 使用resource string.xml
	private static final String[] WEEKS = new String[] { "������", "����һ", "���ڶ�", "������", "������", "������", "������" };
	private static final String TODAY = "����";

	public static Date parseDate(String text, String pattern) {
		try {
			SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.getDefault());
			return sdf.parse(text);
		} catch (ParseException e) {
			Log.w(TAG, "parseDate ParseException");
		}
		return null;
	}

	public static Date parseDate(String text) {
		return parseDate(text, PATTERN_DATE);
	}

	public static Date parseTime(String text) {
		return parseDate(text, PATTERN_TIME);
	}

	public static String formatDate(Date date, String pattern) {
		SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.getDefault());
		return sdf.format(date);
	}

	public static String formatDate(Date date) {
		return formatDate(date, PATTERN_DATE);
	}

	public static String formatDate2(Date date) {
		return formatDate(date, PATTERN_DATE2);
	}

	public static String formatShortDate(Date date) {
		return formatDate(date, PATTERN_SHORT_DATE);
	}

	public static String formatTime(Date date) {
		return formatDate(date, PATTERN_TIME);
	}

	public static String formatMiddTime(Date date) {
		return formatDate(date, PATTERN_MIDD_TIME);
	}

	public static String formatShortTime(Date date) {
		return formatDate(date, PATTERN_SHORT_TIME);
	}

	public static String formatDateTime(Date date) {
		return formatDate(date, PATTERN_DATE_TIME);
	}

	public static String formatWeek(Date date) {
		Calendar cal = Calendar.getInstance();
		int today = cal.get(Calendar.DAY_OF_WEEK);
		cal.setTime(date);
		int week = cal.get(Calendar.DAY_OF_WEEK);
		if (week == today) return TODAY;
		return WEEKS[week - 1];
	}

	public static Date getDateNow() {
		return Calendar.getInstance().getTime();
	}

	/**
	 * @Description: 取得不包含时间的日期
	 * @param date
	 * @return
	 */
	public static Date getDateNoTime(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.clear(Calendar.HOUR_OF_DAY);
		cal.clear(Calendar.MINUTE);
		cal.clear(Calendar.SECOND);
		cal.clear(Calendar.MILLISECOND);
		return cal.getTime();
	}

	public static Date getDateAdvanceDay(int day) {
		Calendar cal = Calendar.getInstance();
		cal.add(Calendar.DATE, -day);
		return cal.getTime();
	}

	/**
	 * @Description: 取前几天，包含今�?
	 * @param day
	 * @return
	 */
	public static Date[] getDateAdvanceDays(int day) {
		Date[] days = new Date[day];
		for (int i = 0; i < day; i++) {
			Calendar cal = Calendar.getInstance();
			cal.add(Calendar.DATE, i + 1 - day);
			days[i] = cal.getTime();
		}
		return days;
	}

	public static Date getDateDelayDay(int day) {
		Calendar cal = Calendar.getInstance();
		cal.add(Calendar.DATE, day);
		return cal.getTime();
	}

	/**
	 * 得到屏幕宽度
	 * 
	 * @return 单位:px
	 */
	public static int getScreenWidth(Context context) {
		int screenWidth = 0;
		WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
		DisplayMetrics dm = new DisplayMetrics();
		wm.getDefaultDisplay().getMetrics(dm);
		screenWidth = dm.widthPixels;
		return screenWidth;
	}

	/**
	 * 转动图片
	 */
	private static int sCenterX, sCenterY;
	private static int sRotateX = 0, sRotateY = 20, sRotateZ = 0;
	private static float skewX = -0.0f, skewY = 0.05f;

	public static Bitmap rotateImage(Bitmap b) {
		Camera camera = new Camera();
		// 获取待处理的图像
		Bitmap tmpBit = b;
		int bWidth = tmpBit.getWidth();
		int bHeight = tmpBit.getHeight();
		sCenterX = bWidth >> 1;
		sCenterY = bHeight >> 1;
		// 记录�?��初始状�?。save()和restore()可以将图像过渡得柔和�?���?
		camera.save();
		Matrix matrix = new Matrix();
		// rotate
		camera.rotateX(sRotateX);
		camera.rotateY(sRotateY);
		camera.rotateZ(sRotateZ);
		// translate
		camera.translate(0, 0, 0);
		camera.getMatrix(matrix);
		matrix.preTranslate(-sCenterX, -sCenterY);
		matrix.postTranslate(sCenterX, sCenterY);
		// 恢复到之前的初始状�?�?
		camera.restore();
		// 设置图像处理的中心点
		matrix.preTranslate(tmpBit.getWidth() >> 1, tmpBit.getHeight() >> 1);
		matrix.preSkew(skewX, skewY);
		// 2.通过矩阵生成新图�?或直接作用于Canvas)
		Bitmap newBit = null;
		try {
			// 经过矩阵转换后的图像宽高有可能不大于0，此时会抛出IllegalArgumentException
			newBit = Bitmap.createBitmap(tmpBit, 0, 0, tmpBit.getWidth(), tmpBit.getHeight(), matrix, true);
		} catch (IllegalArgumentException iae) {
			iae.printStackTrace();
		}
		return newBit;
	}

	public static PopupWindow newInstance(View contentView, int width, int height) {
		PopupWindow pop = new PopupWindow(contentView, width, height, false);
		// pop.setBackgroundDrawable(new BitmapDrawable());
		pop.setOutsideTouchable(true);
		pop.setFocusable(true);
		return pop;
	}

	// TODO yangzhilin, 2014/10/22 现在暂时处理双引�? 没有找到更好方法处理rtsp串中�?��特殊字符�?
	public static String encode(String url) {
		if (null != url) {
			url = url.replace("\"", "\'");
		}
		return url;
	}

}
